package com.parsifal.server.socket;

import android.util.Log;

import com.parsifal.server.callback.PortAllocatedCallback;
import com.parsifal.server.callback.SocketStateCallback;

import java.io.BufferedInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * Created by yangming on 17-3-31.
 */
public class Server {

    private static final String TAG = Server.class.getSimpleName();

    private int mPort = 0;

    private Socket mSocket = null;

    private boolean mServerRun = false;

    private SocketStateCallback mSocketStateCallback = null;

    private PortAllocatedCallback mPortAllocatedCallback = null;

    private ExecutorService mThreadPool = null;

    public void listen() {
        if (!mServerRun) {
            mThreadPool = Executors.newSingleThreadExecutor();
            Runnable socketThread = new Runnable() {
                @Override
                public void run() {
                    while (!mServerRun) {
                        try {
                            ServerSocket serverSocket = new ServerSocket(0); //读取空闲的可用端口
                            mPort = serverSocket.getLocalPort();
                            if (null != mPortAllocatedCallback) {
                                mPortAllocatedCallback.onAllocated(mPort);
                            }
                            mSocket = serverSocket.accept();
                            if (null != mSocketStateCallback) {
                                mSocketStateCallback.onConnected();
                            }
                            serverSocket.close();
                            mServerRun = true;
                            while (mServerRun) {
                                InputStream inputStream = mSocket.getInputStream();
                                byte[] buffer = new byte[1024];
                                BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream);
                                int length = bufferedInputStream.read(buffer);
                                String clientMsg = new String(buffer, 0, length);
                                if (null != mSocketStateCallback) {
                                    mSocketStateCallback.onReceive(clientMsg);
                                }

                                OutputStream outputStream = mSocket.getOutputStream();
                                String serverMsg = "hello " + clientMsg;
                                outputStream.write(serverMsg.getBytes());
                                outputStream.flush();
                                if (null != mSocketStateCallback) {
                                    mSocketStateCallback.onSend(serverMsg);
                                }
                            }
                        } catch (Exception e) {
                            try {
                                mSocket.close();
                                mServerRun = false;
                                if (null != mSocketStateCallback) {
                                    mSocketStateCallback.onDisconnected();
                                }
                            } catch (Exception e1) {
                                e1.printStackTrace();
                            }
                            e.printStackTrace();
                        }
                    }

                }
            };
            mThreadPool.execute(socketThread);
            Log.i(TAG, "服务端 ON");
        }
    }

    public void setSocketStateCallback(SocketStateCallback callback) {
        this.mSocketStateCallback = callback;
    }

    public void setOnPortAllocatedListener(PortAllocatedCallback listener) {
        this.mPortAllocatedCallback = listener;
    }

    public int getPort() {
        return mPort;
    }

    public void stopServer() {
        mServerRun = false;
        if (null != mSocket) {
            try {
                mSocket.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        if (null != mThreadPool) {
            mThreadPool.shutdownNow();
        }
    }
}
